package com.baishui.gateway.classloader;

import com.baishui.gateway.utils.StringUtilsExt;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

public class GateWayClassLoader extends ClassLoader {

    private ConcurrentHashMap<String, byte[]> classSource = new ConcurrentHashMap<>();

    private static GateWayClassLoader classLoader = new GateWayClassLoader();

    /**
     * @param name
     * @return
     */
    @Override
    public URL getResource(String name) {
        /**
         * TODO ???
         */
        try {
            if (name.contains("String.class") || name.contains("Class.class") || name.contains(
                    "Object.class") || name.contains("Throwable.class") || name.contains(
                    "IllegalArgumentException.class")) {
                return null;
            }
            String s = String.format("%s%s", "file:classpath/", name);
            return new URL(s);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public InputStream getResourceAsStream(String name) {
        String s = StringUtilsExt.replaceClassName(name);
        byte[] bytes = classSource.get(s);
        return new ByteArrayInputStream(bytes);
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        Class<?> loadedClass = this.findLoadedClass(name);
        if (Objects.nonNull(loadedClass)) {
            return loadedClass;
        }
        byte[] bytes = classSource.get(name);
        if (Objects.nonNull(bytes)) {
            Class<?> aClass = defineClass(name, bytes, 0, bytes.length);
            return aClass;
        }
        return null;
    }

    private GateWayClassLoader() {
    }

    public static GateWayClassLoader getInstance() {
        return classLoader;
    }

    public void initClassLoader(String className, byte[] clazzSource) {
        classSource.put(className, clazzSource);
    }

    public byte[] getClazzSourceByName(String className){
        return classSource.get(className);
    }

    public Map<String, byte[]> getClazzSource(){
        return classSource;
    }

}
